from logging import Logger
from pathlib import Path
from time import sleep
import yaml
import traceback
from playwright.sync_api import Page
from .network_monitor import NetworkMonitor
from common.auth import login, check_storage_file_exists
from common.env import load_pw_config
from common.browser import start_browser, close_browser
from performance.runner.logger import create_step_logger
from performance.runner.constants import TESTCASE_LIST_PATH


def exec_network_monitor(feature_category: str, network_log_path: Path, csv: bool = False):
    step_logger = create_step_logger(network_log_path, feature_category)
    step_logger.info('=' * 80)
    step_logger.info('Network monitor new round start!')
    step_logger.info('=' * 80)

    # 加载任务列表
    testcases = _load_testcases(feature_category)
    if not testcases:
        step_logger.info('未找到目标API或用例，退出任务...')
        return
    
    # 收集所有不重复的targetAPIs
    target_apis = []
    seen_apis = set()
    for module in testcases['modules']:
        for func in module['functions']:
            for api in func['targetAPIs']:
                api_tuple = (api['path'], api['method'])
                if api_tuple not in seen_apis:
                    seen_apis.add(api_tuple)
                    target_apis.append(api)

    monitor = NetworkMonitor(feature_category, step_logger, network_log_path)
    playwright = browser = context = page = None
    try:
        # 加载环境变量
        pw_config = load_pw_config()
        context_config = pw_config['context']
        check_storage_file_exists(context_config['storage_state'])
        step_logger.info(f"Playwright上下文环境变量: {context_config}")

        # 启动浏览器
        playwright, browser, context, page = start_browser(base_url=context_config['base_url'], storage_state=context_config['storage_state'])
        client = context.new_cdp_session(page)       
        step_logger.info('启动Playwright浏览器') 

        # 登录
        login(context, pw_config['credentials'])
        step_logger.info('验证成功') 

        for module in testcases['modules']:
            for func in module['functions']:
                func_full = f'{testcases['dir']}{module['name']}::{func['name']}'
                step_logger.info(f"即将执行用例: {func_full}")
                # 开始监控
                monitor.start_monitoring(client, func['name'], func['targetAPIs'])
                # 执行任务
                _exec_task(testcase_name = func['name'], testcase_file = module['name'], testcase_dir = testcases['dir'], page = page, step_logger = step_logger)
                sleep(1)
                # 停止监控
                monitor.stop_monitoring(client)
            
    except Exception as e:
        step_logger.error(f'监控过程中发生错误: {e} \n {traceback.format_exc()}')
    finally:
        # 关闭浏览器
        if browser or playwright:
            close_browser(browser, playwright)

    if not csv:
        return

    step_logger.info(f'输出结果到csv...')
    parsed_data = monitor.log_parser.process_all_logs(target_apis)
    if parsed_data:
        monitor.log_parser.save_to_csv(parsed_data, network_log_path / 'result.csv')


def _load_testcases(feature_category) -> list:
    """
    加载测试用例配置文件，提取指定特性的测试用例信息。
    
    Args:
        feature_category: 特性类别名称
    
    Returns:
        list: 测试用例信息列表，每个元素包含 dir, file, function 信息
    """
    # 加载 YAML 配置文件
    with open(TESTCASE_LIST_PATH, 'r', encoding='utf-8') as file:
        yaml_config = yaml.safe_load(file)
    
    # 检查特性是否存在 - yaml_config是数组，查找category等于feature_category的元素
    if not yaml_config:
        return {}
    
    # 查找匹配的category配置
    feature_config = None
    for item in yaml_config:
        if isinstance(item, dict) and item.get('category') == feature_category:
            feature_config = item
            break
    
    if not feature_config:
        return {}
    
    testcases = feature_config.get('testcases', {})
    
    return testcases


def _exec_task(testcase_name, testcase_file, testcase_dir, page: Page, step_logger: Logger):
    """
    执行单个测试用例。
    
    Args:
        testcase_name: 测试用例函数名
        testcase_file: 测试用例文件名
        testcase_dir: 测试用例文件所在目录
        page: 浏览器页面对象
    """
    # 构建导入路径：将目录路径转换为包路径，并添加文件名（去掉.py后缀）
    import_path = f"{testcase_dir.replace('/', '.')}{testcase_file.replace('.py', '')}"
    
    try:
        # 动态导入模块
        module = __import__(import_path, fromlist=[testcase_name])
        
        # 获取函数对象
        function = getattr(module, testcase_name)
        
        # 调用测试函数
        step_logger.info(f"执行测试用例: {testcase_name} 来自 {testcase_file}")
        function(page)
        
    except ImportError as e:
        step_logger.error(f"无法导入模块 {import_path}: {e}, \n {traceback.format_exc()}")
    except AttributeError as e:
        step_logger.error(f"无法在模块 {import_path} 找到函数 {testcase_name} : {e}, \n {traceback.format_exc()}")
    except Exception as e:
        step_logger.error(f"错误: 执行测试用例 {testcase_name} 时发生错误: {e}, \n {traceback.format_exc()}, \n {traceback.format_exc()}")